package com.lty.nio.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/***
 * 
* <p>Title: NIOServer</p>
* <p>Description: NIO服务端</p>
* <p>Company: lty</p>
* @author liuhao
* @date 2017年7月5日 上午10:41:17
 */
public class NIOServer {
	//每次发送数据加标识
	private int flag = 1;
	
	//缓冲区字节大小
	private int blockSize = 4096;
	
	//发送缓冲区
	private ByteBuffer sendBuff = ByteBuffer.allocate(blockSize);
	
	//接收缓冲区
	private ByteBuffer receiveBuff = ByteBuffer.allocate(blockSize);
	
	//选择器
	private Selector selector;
	
	public NIOServer(int port) throws IOException {
		//服务端ServerSocketChannel
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		
		//设置是否阻塞
		serverSocketChannel.configureBlocking(false);
		
		//获取服务端的ServerSocket
		ServerSocket serverSocket = serverSocketChannel.socket();
		
		//绑定ip(默认本机)和端口
		serverSocket.bind(new InetSocketAddress(port));
		
		//打开选择器
		selector = Selector.open();
		
		//serverSocketChannel向selector注册accept事件
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		System.out.println("server started at: " + port);
	}

	//监听客户端连接事件
	private void listen() throws IOException{
		while(true){
			selector.select();
			Set<SelectionKey> selectionKeys = selector.selectedKeys();
			Iterator<SelectionKey> iterator = selectionKeys.iterator();
			
			//遍历selector里面所有SelectionKey
			while(iterator.hasNext()){
				SelectionKey selectionKey = iterator.next();
				
				//清除key元素
				iterator.remove();
				
				//对每个SelectionKey处理相应的IO事件
				handleKey(selectionKey);
			}
			//清除selector所有SelectionKey
			//selectionKeys.clear();
 		}
	}
	
	//处理具体的key
	private void handleKey(SelectionKey selectionKey) throws IOException{
		//服务端的ServerSocketChannel
		ServerSocketChannel server = null;
		
		//客户端的SocketChannel
		SocketChannel client = null;
		
		String sendText;
		String receiveText;
		int count = 0;
		
		//服务端连接客户端请求accept事件就绪
		if(selectionKey.isAcceptable()){
			//这里是ServerSocketChannel
			server = (ServerSocketChannel) selectionKey.channel();
			
			//client由server获取SocketChannel通道
			client = server.accept();
			client.configureBlocking(false);
			
			//client向selector注册read事件
			client.register(selector, SelectionKey.OP_READ);
			System.out.println("server ready to read...");
		}
		//client的read事件
		if(selectionKey.isReadable()){
			//这里必须加上清空命令，否则缓冲区会保留上次读取结果
			receiveBuff.clear();
			client = (SocketChannel) selectionKey.channel();
			count = client.read(receiveBuff);
			
			if(count > 0){
				receiveText = new String(receiveBuff.array(), 0, count);
				System.out.println("server received from client: " + receiveText);
				
				//client向selector注册write事件
				client.register(selector, SelectionKey.OP_WRITE);
			}
		}
		//client的write事件
		if(selectionKey.isWritable()){
			//这里必须加上清空命令，否则缓冲区会保留上次写入结果
			sendBuff.clear();
			client = (SocketChannel) selectionKey.channel();

			//要发送的文本信息
			sendText = "Hello client!——times: " + flag++;
			sendBuff.put(sendText.getBytes());
			sendBuff.flip();
			client.write(sendBuff);
			
			System.out.println("server sent msg to client: " + sendText);
			
			//client向selector注册read事件
			client.register(selector, SelectionKey.OP_READ);
		}
	}

	public static void main(String[] args) throws IOException {
		NIOServer nioServer = new NIOServer(2017);
		nioServer.listen();
	}

}
